import QupComponents from 'qup-component'
const isType = (v, type) => {
  return Object.prototype.toString.call(v).toLowerCase() === `[object ${type}]`.toLowerCase()
}
function deepCopy(src) {
  if (isType(src, 'Array')) {
    return src.map(e => deepCopy(e))
  } else if (isType(src, 'Object')) {
    const tmp = {}
    Object.entries(src).forEach(([k, v]) => {
      tmp[k] = deepCopy(v)
    })
    return tmp
  } else {
    return src
  }
}
export default {
  extends: QupComponents.searchForm,
  props: {
    // 是否默认展开
    defaultUnfold: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      dependencies: {},
      inputListeners: {}
    }
  },
  methods: {
    collectDependencies() {
      const dependencies = {}
      const inputListeners = {}
      for (const c of this.searchConfig) {
        if (c.parentListeners) {
          for (const [parentProp, listener] of Object.entries(c.parentListeners)) {
            let p = dependencies[parentProp]
            if (!p) {
              dependencies[parentProp] = []
              p = dependencies[parentProp]
            }
            p.push({
              parentProp,
              config: c,
              listener
            })
          }
        }
        if (c.inputListener) {
          c.config.remote = false
          inputListeners[c.prop] = {
            listener: c.inputListener,
            config: c,
            _config: deepCopy(c)
          }
        }
      }
      this.dependencies = dependencies
      const i = Object.entries(this.inputListeners)
      if (i.length > 0) {
        i.forEach(e => {
          e.unwatch && e.unwatch() && (delete e.unwatch)
        })
      }
      this.inputListeners = inputListeners
    },
    handlerParentChange(parentProp, parentValue) {
      const de = this.dependencies[parentProp]
      if (de && de.length > 0) {
        de.forEach(e => {
          e.listener && e.listener(parentProp, parentValue, (filtersRaw, paramsRaw) => {
            if (filtersRaw) {
              this.$set(e.config.config, 'filtersRaw', filtersRaw)
              this.$set(e.config.config, 'dialogConfig', filtersRaw)
            }
            if (paramsRaw) {
              this.$set(e.config.config, 'filtersRaw', paramsRaw)
              this.$set(e.config.config, 'dialogConfig', paramsRaw)
            }
            e.config.config.selectData = []
            if (this.inputListeners[e.config.prop]) {
              this.inputListeners[e.config.prop]._config = deepCopy(e.config)
            }
            // this.getSelections(e.config.config, e.config)
          }, (value = '') => {
            this.updateValue(e.config.prop, value)
            this.$set(e.config, 'value', value)
          }, { config: e.config, searchData: this.searchData })
        })
      }
    },
    handlerEditChange(v) {
      const { prop, value } = v
      this.handlerParentChange(prop, value)
    },
    handlerSelectQueryChange(children) {
      for (const c of children) {
        if (['ElFormItem'].includes(c.$options.name)) {
          const t = this.findSelect(c)
          const e = this.inputListeners[c.prop]
          if (!t || !e) continue
          if (!t._remoteSelections) {
            t._remoteSelections = t.remoteSelections
          }
          t.remoteSelections = (v, callback) => {
            const id = (Math.random() * 0xffff).toString()
            const { keywordReg, config } = e.config
            const property = keywordReg ? keywordReg(v) : config.customName
            if (e._config && e._config.config) {
              if (e._config.config.filtersRaw) {
                t.config.filtersRaw = deepCopy(e._config.config.filtersRaw)
              } else {
                t.config.filtersRaw = []
              }
              if (e._config.config.paramsRaw) {
                t.config.paramsRaw = deepCopy(e._config.config.paramsRaw)
              } else {
                t.config.paramsRaw = {}
              }
            } else {
              t.config.filtersRaw = []
              t.config.paramsRaw = {}
            }
            v && t.config.filtersRaw.push({ id: id, property, value: v, operator: 'like' })
            t._remoteSelections(v, (...args) => {
              callback(...args)
            })
          }
          // 处理dialogConfig弹出框搜索
          if (t.$options.name === 'InputWithDialog') {
            if (!t._handleSearch) {
              t._handleSearch = t.handleSearch
              t._openDialog = t.openDialog
              t.openDialog = function(...args) {
                if (e._config && e._config.config) {
                  if (e._config.config.filtersRaw) {
                    t.config.filtersRaw = deepCopy(e._config.config.filtersRaw)
                  } else {
                    t.config.filtersRaw = []
                  }
                  if (e._config.config.paramsRaw) {
                    t.config.paramsRaw = deepCopy(e._config.config.paramsRaw)
                  } else {
                    t.config.paramsRaw = {}
                  }
                } else {
                  t.config.filtersRaw = []
                  t.config.paramsRaw = {}
                }
                t._openDialog.call(this, ...args)
              }
            }
            const id = (Math.random() * 0xffff).toString()
            t.handleSearch = function(...args) {
              const v = t.queryKeyWord ? t.queryKeyWord.trim() : ''
              const { keywordReg, config } = e.config
              const property = keywordReg ? keywordReg(v) : config.customName
              if (e._config && e._config.config) {
                if (e._config.config.filtersRaw) {
                  t.config.filtersRaw = deepCopy(e._config.config.filtersRaw)
                } else {
                  t.config.filtersRaw = []
                }
                if (e._config.config.paramsRaw) {
                  t.config.paramsRaw = deepCopy(e._config.config.paramsRaw)
                } else {
                  t.config.paramsRaw = {}
                }
              } else {
                t.config.filtersRaw = []
                t.config.paramsRaw = {}
              }
              if (v) {
                t.config.filtersRaw.push({ id: id, property, value: v, operator: 'like' })
              }
              t._handleSearch(...args)
            }
          }
          const handler = this.debounce(v => e.listener(v, (filtersRaw, paramsRaw, customName) => {
            if (e.config.config) {
              filtersRaw && (e.config.config.filtersRaw = filtersRaw)
              paramsRaw && (e.config.config.paramsRaw = paramsRaw)
              e.config.config.selectData = []
              if (t.$options.name === 'ElSelect') {
                this.getSelections(e.config.config, e.config)
              }
            }
            if (e.config.dialogConfig) {
              e.config.dialogConfig.remote = false
              filtersRaw && (e.config.dialogConfig.filtersRaw = filtersRaw)
              paramsRaw && (e.config.dialogConfig.paramsRaw = paramsRaw)
            }
          }))
          t.debouncedOnInputChange = handler
          // t.$on('clear', handler)
          const unwatch = t.$watch(t.$options.name === 'InputWithDialog' ? 'selLable' : 'selectedLabel', (v, o) => {
            handler(v)
          })
          e.unwatch = unwatch
          t.$once('hook:beforeDestroy', () => {
            unwatch()
            delete e.unwatch
          })
        }
        if (c.$children) {
          this.handlerSelectQueryChange(c.$children)
        }
      }
    },
    findSelect(component) {
      const cs = component.$children
      if (!cs) return
      for (const c of cs) {
        const name = c.$options.name
        if (name === 'ElSelect' || name === 'InputWithDialog') {
          return c
        }
        const t = this.findSelect(c)
        if (t) {
          return t
        }
      }
    },
    debounce(fn, delayed = 100) {
      let id
      return (...args) => {
        if (id)clearTimeout(id)
        id = setTimeout(() => {
          id = null
          fn(...args)
        }, delayed)
      }
    },
    findChild(children, name) {
      const tmp = []
      for (const c of children) {
        if (c.$options.name === name) {
          tmp.push(c)
        }
        if (c.$children && c.$children.length > 0) {
          const t = this.findChild(c.$children, name)
          if (t && t.length > 0) {
            tmp.push(...t)
          }
        }
      }
      return tmp
    },
    // 处理必填
    handleRequired() {
      if (!this.$children) return
      const efi = this.findChild(this.$children, 'ElFormItem')
      for (const c of this.searchConfig) {
        if (c.required) {
          const t = efi.find(e => e.prop === c.prop)
          if (t) {
            t.required = true
          }
        }
      }
    }
  },
  watch: {
    searchConfig: {
      handler(v) {
        this.collectDependencies()
        this.handleRequired()
      },
      immediate: true
    }
  },
  created() {
    this.collectDependencies()
    this.$on('edit-change', this.handlerEditChange)
  },
  updated() {
    this.handleRequired()
  },
  mounted() {
    if (this.defaultUnfold) {
      this.toggleMore()
    }
    setTimeout(() => { this.handlerSelectQueryChange(this.$children) }, 1000)
    this.unwatchInputListeners = this.$watch('inputListeners', () => {
      setTimeout(() => { this.handlerSelectQueryChange(this.$children) }, 100)
    })
  },
  beforeDestroy() {
    this.$off('edit-change', this.handlerEditChange)
    this.unwatchInputListeners && this.unwatchInputListeners()
  }
}

